package cn.com.idmy.cloud.service.impl;

import cn.com.idmy.base.model.Page;
import cn.com.idmy.base.util.IdUtil;
import cn.com.idmy.base.util.SqlUtil;
import cn.com.idmy.cloud.service.MybatisPlusService;
import cn.com.idmy.orm.core.Tables;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.collection.CollUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

@Slf4j
public class MybatisPlusServiceImpl<D extends MybatisPlusDao<T, ID>, T, ID extends Serializable> implements MybatisPlusService<T, ID> {
    @Autowired
    protected D dao;

    @Override
    public Logger log() {
        return log;
    }

    @Override
    public @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2) {
        return dao.getNullable(q.select(f1, f2));
    }

    @Override
    public @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3) {
        return dao.getNullable(q.select(f1, f2, f3));
    }

    @Override
    public @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2) {
        return dao.get(q.select(f1, f2));
    }

    @Override
    public @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3) {
        return dao.get(q.select(f1, f2, f3));
    }

    @Override
    public @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2) {
        return dao.list(q.select(f1, f2));
    }

    @Override
    public @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3) {
        return dao.list(q.select(f1, f2, f3));
    }

    @Override
    public boolean copy(@NonNull ID id, @NotNull Consumer<T> consumer) {
        var t = get(id);
        consumer.accept(t);
        return create(t);
    }

    @Override
    public boolean create(@NonNull T t) {
        return SqlUtil.toBoolean(dao.create(t));
    }

    @Override
    public boolean create(@NonNull Collection<T> ls) {
        return create(ls, 1000);
    }

    @Override
    public boolean create(@NonNull Collection<T> ls, int size) {
        if (CollUtil.isEmpty(ls)) {
            return false;
        }
        return SqlUtil.toBoolean(dao.create(ls, size));
    }

    @Override
    public boolean copy(@NonNull ID id) {
        return copy(id, t -> {});
    }

    @Override
    public boolean copy(@Nullable Collection<ID> ls) {
        if (CollUtil.isEmpty(ls)) {
            return false;
        }
        for (ID id : ls) {
            copy(id);
        }
        return true;
    }

    @Override
    public boolean update(@NonNull T t) {
        return SqlUtil.toBoolean(dao.update(t));
    }


    @Override
    public boolean update(@Nullable Collection<T> ls, int size) {
        if (CollUtil.isEmpty(ls)) {
            return false;
        } else {
            return SqlUtil.toBoolean(dao.update(ls, size));
        }
    }

    @Override
    public boolean update(@Nullable Collection<T> ls) {
        if (CollUtil.isEmpty(ls)) {
            return false;
        } else {
            return SqlUtil.toBoolean(dao.update(ls, 1000));
        }
    }

    @Override
    public boolean update(@NotNull LambdaUpdateWrapper<T> u) {
        return SqlUtil.toBoolean(dao.update(u));
    }

    @Override
    public boolean createOrUpdate(@NonNull T t) {
        return dao.createOrUpdate(t);
    }

    @Override
    public boolean delete(@NonNull ID id) {
        return SqlUtil.toBoolean(dao.delete(id));
    }

    @Override
    public boolean delete(@Nullable Collection<ID> ids) {
        return SqlUtil.toBoolean(dao.delete(ids));
    }

    @Override
    public boolean delete(@NotNull LambdaQueryWrapper<T> d) {
        return SqlUtil.toBoolean(dao.delete(d));
    }

    @Override
    public @NotNull ID newId() {
        var id = Tables.getId(dao.entityType());
        return IdUtil.getId(dao.idType(), dao.table().getEntityType(), id.value());
    }

    public @NotNull TableInfo table() {
        return dao.table();
    }

    @Override
    public @NotNull LambdaQueryWrapper<T> q() {
        return dao.q();
    }

    public @NotNull LambdaUpdateWrapper<T> u() {
        return dao.u();
    }

    public @NotNull LambdaQueryWrapper<T> d() {
        return dao.d();
    }

    public long count(@NotNull LambdaQueryWrapper<T> q) {
        return dao.count(q);
    }

    public boolean has(@NotNull LambdaQueryWrapper<T> q) {
        return dao.has(q);
    }

    @Override
    public boolean has(@NonNull ID id) {
        return dao.has(id);
    }

    @Override
    public void has(@NonNull ID id, @NotNull String msg, @NotNull Object... params) {
        dao.has(id, msg, params);
    }

    public void has(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params) {
        dao.has(q, msg, params);
    }

    public boolean notHas(@NotNull LambdaQueryWrapper<T> q) {
        return dao.notHas(q);
    }

    @Override
    public boolean notHas(@NonNull ID id) {
        return dao.notHas(id);
    }

    @Override
    public void notHas(@NonNull ID id, @NotNull String msg, @NotNull Object... params) {
        dao.notHas(id, msg, params);
    }

    public void notHas(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params) {
        dao.notHas(q, msg, params);
    }

    public @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q) {
        return dao.list(q);
    }

    @Override
    public @NotNull List<T> all() {
        return dao.all();
    }

    @Override
    public @NotNull List<T> list(@Nullable Collection<ID> ids) {
        return dao.list(ids);
    }

    @Override
    public @NotNull List<T> list(@NotNull Collection<ID> ids, @NotNull String msg, @NotNull Object... params) {
        return dao.list(ids, msg, params);
    }

    @Override
    public @NotNull <R> List<R> list(@NotNull SFunction<T, R> field, @Nullable Collection<ID> ids) {
        return dao.list(field, ids);
    }

    @Override
    public @NotNull <R> List<R> list(@NotNull SFunction<T, R> field, @NotNull LambdaQueryWrapper<T> q) {
        return dao.list(field, q);
    }

    @Override
    public @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q) {
        return dao.getNullable(q);
    }

    @Override
    public @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params) {
        return dao.get(q, msg, params);
    }

    @Override
    public @NotNull T get(@NotNull LambdaQueryWrapper<T> q) {
        return dao.get(q);
    }

    @Override
    public @Nullable T getNullable(@NonNull ID id) {
        return dao.getNullable(id);
    }

    @Override
    public @NotNull T get(@NonNull ID id) {
        return dao.get(id);
    }

    @Override
    public <R> @Nullable R getNullable(@NotNull SFunction<T, R> field, @NonNull ID id) {
        return dao.getNullable(field, id);
    }

    @Override
    public <R> @NotNull R get(@NotNull SFunction<T, R> field, @NonNull ID id) {
        return dao.get(field, id);
    }

    @Override
    public <R> @NotNull R get(@NotNull SFunction<T, R> field, @NonNull ID id, @NotNull String msg, @NotNull Object... params) {
        return dao.get(field, id, msg, params);
    }

    @Override
    public <R> @Nullable R getNullable(@NotNull SFunction<T, R> field, @NotNull LambdaQueryWrapper<T> q) {
        return dao.getNullable(field, q);
    }

    @Override
    public <R> @NotNull R get(@NotNull SFunction<T, R> field, @NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params) {
        return dao.get(field, q, msg, params);
    }

    @Override
    public <R> @NotNull R get(@NotNull SFunction<T, R> field, @NotNull LambdaQueryWrapper<T> q) {
        return dao.get(field, q);
    }

    @Override
    public @NotNull Map<ID, T> map(@Nullable ID[] ids) {
        return dao.map(ids);
    }

    @Override
    public @NotNull Map<ID, T> map(@Nullable Collection<ID> ids) {
        return dao.map(ids);
    }

    public @NotNull <R> Map<R, T> map(@NotNull SFunction<T, R> field, @NotNull LambdaQueryWrapper<T> q) {
        return dao.map(field, q);
    }

    @Override
    public @NotNull Page<T> page(@NonNull Page<?> in, @NotNull QueryWrapper<T> q) {
        return dao.page(in, q);
    }

    @Override
    public @NotNull Page<T> page(@NotNull Page<?> in) {
        return dao.page(in, new QueryWrapper<>());
    }

    @Override
    public @NotNull Page<T> page(@NotNull Page<?> in, @NotNull LambdaQueryWrapper<T> q) {
        return dao.page(in, q);
    }
}